package weeny.cluster;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

import kc.test.kmeans.Centroid;
import kc.test.kmeans.KMeansAlgorithm;
import kc.test.kmeans.Point;

class ObjPoint extends Point{
	//piggy back the object corresponding to this Point
	public Object obj = null;
	public ObjPoint(double...ds) {
		super(ds);
	}
}

public abstract class AbstractKmeans {
	
	public static Random rand = new Random(123456L);
	
	
	protected abstract double[] toVector(Object o);
	
	private Set<Color> usedColor = new HashSet<Color>();
	
	protected Color newColor(){
		Color newColor = new Color(rand.nextInt());
		while (usedColor.contains(newColor)) {
			newColor = new Color(rand.nextInt());
		}
		usedColor.add(newColor);
		return newColor;
	}
	
	public Set cluster(Iterator iter, Collection seeds){
		ArrayList objects = new ArrayList();
		while (iter.hasNext()){
			objects.add(iter.next());
		}
		return cluster(objects, seeds);
	}
	
	public Set cluster(Collection objects, Collection seeds){
		ArrayList<Point>  points = new ArrayList<Point>();
		for (Object obj : objects) {
			ObjPoint pnt = new ObjPoint(toVector(obj));
			pnt.obj = obj;
			points.add(pnt);
		}
		
		ArrayList<Centroid> centroids = new ArrayList<Centroid>();
		for(Object obj : seeds){
			centroids.add(new Centroid(new Point(toVector(obj)), newColor()));
		}
		KMeansAlgorithm alg = new KMeansAlgorithm();
		alg.init(points, centroids);
		alg.run();
		Set<Set> result = new HashSet<Set>();
		for(Centroid cent : centroids) {
			Set set = new HashSet();
			for(Point p : cent.getPoints()) {
				Object obj = ((ObjPoint)p).obj;
				if (obj == null) {
					throw new IllegalStateException();
				}
				set.add(obj);
			}
			result.add(set);
		}
		return result;
	}
	
	public Set cluster(Iterator iter, int clusterCnt){
		ArrayList objects = new ArrayList();
		while (iter.hasNext()){
			objects.add(iter.next());
		}
		ArrayList seeds = new ArrayList();
		for (int i = 0; i<clusterCnt; i++){
			seeds.add(objects.get(rand.nextInt(objects.size()-1)));
		}
		return cluster(objects, seeds);
	}
}